package com.example.service.impl;

import com.example.domain.dto.MoneyDTO;
import com.example.domain.dto.pricelist.*;
import com.example.domain.dto.product.ProductListItemDTO;
import com.example.domain.entity.PriceList;
import com.example.domain.entity.PriceListEntry;
import com.example.domain.entity.Product;
import com.example.domain.entity.Unit;
import com.example.domain.entity.enums.PriceListStatus;
import com.example.domain.entity.enums.ProductStatus;
import com.example.domain.repository.PriceListEntryRepository;
import com.example.domain.repository.PriceListRepository;
import com.example.domain.repository.ProductRepository;
import com.example.domain.repository.UnitRepository;
import com.example.domain.valueobject.DiscountResult;
import com.example.domain.valueobject.Money;
import com.example.exception.BusinessException;
import com.example.exception.ErrorCode;
import com.example.exception.ResourceNotFoundException;
import com.example.service.PriceListService;
import com.example.service.PromotionService;
import com.example.util.IdGenerator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 价目表服务实现类
 * 
 * @author Means
 * @since 2025-10-27
 */
@Slf4j
@Service
@Transactional(readOnly = true)
public class PriceListServiceImpl implements PriceListService {
    
    private final PriceListRepository priceListRepository;
    private final PriceListEntryRepository priceListEntryRepository;
    private final ProductRepository productRepository;
    private final PromotionService promotionService;
    private final UnitRepository unitRepository;

    public PriceListServiceImpl(PriceListRepository priceListRepository,
                               PriceListEntryRepository priceListEntryRepository,
                               ProductRepository productRepository,
                               PromotionService promotionService,
                               UnitRepository unitRepository) {
        this.priceListRepository = priceListRepository;
        this.priceListEntryRepository = priceListEntryRepository;
        this.productRepository = productRepository;
        this.promotionService = promotionService;
        this.unitRepository = unitRepository;
    }
    
    // ==================== 价目表管理 ====================
    
    @Override
    @Transactional
    public PriceListDTO createPriceList(CreatePriceListRequest request) {
        log.info("创建价目表: name={}", request.getName());
        
        // 构建价目表实体
        PriceList priceList = new PriceList();
        priceList.setId(IdGenerator.generate());
        priceList.setName(request.getName());
        priceList.setEffectiveFrom(request.getEffectiveFrom());
        priceList.setEffectiveTo(request.getEffectiveTo());
        priceList.setStatus(request.getStatus() != null ? request.getStatus() : PriceListStatus.INACTIVE);
        
        // 保存
        priceList = priceListRepository.save(priceList);
        
        log.info("价目表创建成功: id={}, name={}", priceList.getId(), priceList.getName());
        return PriceListDTO.from(priceList);
    }
    
    @Override
    @Transactional
    public PriceListDTO updatePriceList(String id, UpdatePriceListRequest request) {
        log.info("更新价目表: id={}", id);
        
        // 查询价目表
        PriceList priceList = priceListRepository.findByIdAndNotDeleted(id)
                .orElseThrow(() -> new ResourceNotFoundException("价目表", id));
        
        // 更新字段
        if (request.getName() != null) {
            priceList.setName(request.getName());
        }
        if (request.getEffectiveFrom() != null) {
            priceList.setEffectiveFrom(request.getEffectiveFrom());
        }
        if (request.getEffectiveTo() != null) {
            priceList.setEffectiveTo(request.getEffectiveTo());
        }
        if (request.getStatus() != null) {
            priceList.setStatus(request.getStatus());
        }
        
        // 保存
        priceList = priceListRepository.save(priceList);
        
        log.info("价目表更新成功: id={}", id);
        return PriceListDTO.from(priceList);
    }
    
    @Override
    public PriceListDTO getPriceListById(String id) {
        log.debug("查询价目表详情: id={}", id);
        
        PriceList priceList = priceListRepository.findByIdAndNotDeleted(id)
                .orElseThrow(() -> new ResourceNotFoundException("价目表", id));
        
        return PriceListDTO.from(priceList);
    }
    
    @Override
    @Transactional
    public void deletePriceList(String id) {
        log.info("删除价目表: id={}", id);
        
        PriceList priceList = priceListRepository.findByIdAndNotDeleted(id)
                .orElseThrow(() -> new ResourceNotFoundException("价目表", id));
        
        if (priceList.getStatus() == PriceListStatus.ACTIVE) {
            throw new BusinessException(ErrorCode.OPERATION_FAILED,
                    String.format("价目表【%s】处于激活状态，请先停用后再删除。", priceList.getName()));
        }
        
        // 软删除关联的价格条目
        priceListEntryRepository.softDeleteByPriceListId(id);
        
        // 软删除价目表
        priceListRepository.softDelete(id);
        
        log.info("价目表删除成功: id={}, name={}", id, priceList.getName());
    }
    
    
    @Override
    public List<PriceListSummaryDTO> getAllPriceLists() {
        log.debug("查询所有价目表");
        
        List<PriceList> priceLists = priceListRepository.findByIsDeleted(false);
        return priceLists.stream()
                .map(PriceListSummaryDTO::from)
                .collect(Collectors.toList());
    }
    
    @Override
    public List<PriceListSummaryDTO> getPriceListsByStatus(PriceListStatus status) {
        log.debug("按状态查询价目表: status={}", status);
        
        List<PriceList> priceLists = priceListRepository.findByStatusAndIsDeleted(status, false);
        return priceLists.stream()
                .map(PriceListSummaryDTO::from)
                .collect(Collectors.toList());
    }
    
    // ==================== 价目表激活/停用 ====================
    
    @Override
    @Transactional
    public PriceListDTO activatePriceList(String id) {
        log.info("激活价目表: id={}", id);
        
        PriceList priceList = priceListRepository.findByIdAndNotDeleted(id)
                .orElseThrow(() -> new ResourceNotFoundException("价目表", id));
        
        // 检查生效时间
        LocalDateTime now = LocalDateTime.now();
        if (priceList.getEffectiveFrom() != null && priceList.getEffectiveFrom().isAfter(now)) {
            throw new BusinessException(ErrorCode.OPERATION_FAILED, 
                    "价目表尚未到生效时间: " + priceList.getEffectiveFrom());
        }
        if (priceList.getEffectiveTo() != null && priceList.getEffectiveTo().isBefore(now)) {
            throw new BusinessException(ErrorCode.OPERATION_FAILED, 
                    "价目表已过期: " + priceList.getEffectiveTo());
        }
        
        // 检查价目表中的所有商品是否都已上架
        List<PriceListEntry> entries = priceListEntryRepository
                .findByPriceListIdAndIsDeleted(id, false);

        if (!entries.isEmpty()) {
            // 获取所有商品ID
            List<String> productIds = entries.stream()
                    .map(PriceListEntry::getProductId)
                    .distinct()
                    .collect(Collectors.toList());
            
            // 批量查询商品
            List<Product> products = productRepository.findByIdsAndNotDeleted(productIds);
            
            // 🆕 检查是否有商品不存在或已删除
            if (products.size() < productIds.size()) {
                Set<String> foundProductIds = products.stream()
                        .map(Product::getId)
                        .collect(Collectors.toSet());
                List<String> missingProductIds = productIds.stream()
                        .filter(missingProductId -> !foundProductIds.contains(missingProductId))
                        .collect(Collectors.toList());
                
                throw new BusinessException(ErrorCode.OPERATION_FAILED,
                        "价目表包含已删除或不存在的商品（商品ID: " + String.join(", ", missingProductIds) + "），无法激活");
            }
            
            // 检查是否有下架商品
            List<String> inactiveProducts = products.stream()
                    .filter(p -> p.getStatus() == ProductStatus.INACTIVE)
                    .map(Product::getName)
                    .collect(Collectors.toList());
            
            if (!inactiveProducts.isEmpty()) {
                throw new BusinessException(ErrorCode.OPERATION_FAILED,
                        "价目表包含已下架的商品，无法激活: " + String.join(", ", inactiveProducts));
            }
        }

        // 停用所有其他已激活的价目表（确保同时只有一个激活）
        List<PriceList> activePriceLists = priceListRepository
                .findByStatusAndIsDeleted(PriceListStatus.ACTIVE, false);
        
        for (PriceList activePriceList : activePriceLists) {
            if (!activePriceList.getId().equals(id)) {
                activePriceList.setStatus(PriceListStatus.INACTIVE);
                priceListRepository.save(activePriceList);
                log.info("自动停用价目表: id={}, name={}", 
                        activePriceList.getId(), activePriceList.getName());
            }
        }
        
        // 激活目标价目表
        priceList.setStatus(PriceListStatus.ACTIVE);
        priceList = priceListRepository.save(priceList);
        
        log.info("价目表激活成功: id={}", id);
        return PriceListDTO.from(priceList);
    }
    
    @Override
    @Transactional
    public PriceListDTO deactivatePriceList(String id) {
        log.info("停用价目表: id={}", id);
        
        PriceList priceList = priceListRepository.findByIdAndNotDeleted(id)
                .orElseThrow(() -> new ResourceNotFoundException("价目表", id));
        
        priceList.setStatus(PriceListStatus.INACTIVE);
        priceList = priceListRepository.save(priceList);
        
        log.info("价目表停用成功: id={}", id);
        return PriceListDTO.from(priceList);
    }
    
    @Override
    public PriceListDTO getCurrentEffectivePriceList() {
        log.debug("查询当前生效的价目表");
        
        return priceListRepository.findCurrentEffectivePriceList(LocalDateTime.now())
                .map(PriceListDTO::from)
                .orElse(null);
    }
    
    
    // ==================== 价目表条目管理 ====================
    
    @Override
    @Transactional
    public PriceListEntryDTO addPriceEntry(String priceListId, AddPriceEntryRequest request) {
        log.info("添加价格条目: priceListId={}, productId={}", priceListId, request.getProductId());
        
        // 1. 检查价目表是否存在
        if (!priceListRepository.findByIdAndNotDeleted(priceListId).isPresent()) {
            throw new ResourceNotFoundException("价目表", priceListId);
        }
        
        // 2. 检查商品是否存在
        if (!productRepository.findByIdAndNotDeleted(request.getProductId()).isPresent()) {
            throw new ResourceNotFoundException("商品", request.getProductId());
        }
        
        // 3. 检查是否已存在该商品的价格条目
        priceListEntryRepository.findByPriceListIdAndProductIdAndIsDeleted(priceListId, request.getProductId(), false)
                .ifPresent(entry -> {
                    throw new BusinessException(ErrorCode.OPERATION_FAILED, 
                            "该商品的价格条目已存在");
                });
        
        // 4. 构建价格条目实体
        PriceListEntry entry = new PriceListEntry();
        entry.setId(IdGenerator.generate());
        entry.setPriceListId(priceListId);
        entry.setProductId(request.getProductId());
        entry.setUnitPrice(request.getUnitPrice());
        entry.setBaseUnit(request.getBaseUnit());
        
        // 5. 保存
        entry = priceListEntryRepository.save(entry);
        
        log.info("价格条目添加成功: id={}", entry.getId());
        return PriceListEntryDTO.from(entry);
    }
    
    @Override
    @Transactional
    public PriceListEntryDTO updatePriceEntry(String entryId, Money unitPrice, String saleUnit) {
        log.info("更新价格条目: entryId={}", entryId);
        
        PriceListEntry entry = priceListEntryRepository.findById(entryId)
                .orElseThrow(() -> new ResourceNotFoundException("价格条目", entryId));
        
        if (unitPrice != null) {
            entry.setUnitPrice(unitPrice.getAmount());
        }
        if (saleUnit != null) {
            entry.setBaseUnit(saleUnit);
        }
        
        entry = priceListEntryRepository.save(entry);
        
        log.info("价格条目更新成功: id={}", entryId);
        return PriceListEntryDTO.from(entry);
    }
    
    @Override
    @Transactional
    public void deletePriceEntry(String entryId) {
        log.info("删除价格条目: entryId={}", entryId);
        
        PriceListEntry entry = priceListEntryRepository.findById(entryId)
                .orElseThrow(() -> new ResourceNotFoundException("价格条目", entryId));
        
        // 软删除：更新删除标记和删除时间
        entry.setIsDeleted(true);
        entry.setDeletedAt(LocalDateTime.now());
        priceListEntryRepository.save(entry);
        
        log.info("价格条目软删除成功: id={}", entryId);
    }
    
    @Override
    // @Transactional(readOnly = true) // 可选：Spring 读事务
    public List<PriceListEntryDTO> getPriceEntriesByPriceList(String priceListId) {
        log.debug("查询价目表的所有条目: priceListId={}", priceListId);
        
        // 1. 查询所有价格条目
        List<PriceListEntry> entries = priceListEntryRepository
                .findByPriceListIdAndIsDeleted(priceListId, false);
        if (entries.isEmpty()) {
            return Collections.emptyList();
        }
        
        // 2. 批量查询商品信息（避免N+1问题）
        Set<String> productIds = entries.stream()
                .map(PriceListEntry::getProductId)
                .filter(id -> id != null && !id.trim().isEmpty())
                .collect(Collectors.toSet());
        
        // 3. 构建商品ID->名称映射
        Map<String, String> productNameMap = productIds.isEmpty()
                ? Collections.emptyMap()
                : productRepository.findAllById(productIds).stream()
                    .collect(Collectors.toMap(
                            Product::getId,
                            Product::getName,
                            (left, right) -> left
                    ));
        
        // 4. 批量查询单位信息（避免N+1问题）
        Set<String> unitCodes = entries.stream()
                .map(PriceListEntry::getBaseUnit)
                .filter(code -> code != null && !code.trim().isEmpty())
                .collect(Collectors.toSet());
        
        // 5. 构建单位代码->名称映射
        Map<String, String> unitNameMap = unitCodes.isEmpty()
                ? Collections.emptyMap()
                : unitRepository.findAllById(new java.util.ArrayList<>(unitCodes)).stream()
                    .collect(Collectors.toMap(
                            Unit::getCode,
                            Unit::getName,
                            (left, right) -> left
                    ));
        
        // 6. 映射为DTO并回填商品名称和单位名称
        return entries.stream()
                .map(entry -> {
                    PriceListEntryDTO dto = PriceListEntryDTO.from(entry);
                    
                    // 回填商品名称
                    String productId = entry.getProductId();
                    if (productId != null && !productId.trim().isEmpty()) {
                        String name = productNameMap.get(productId);
                        if (name != null) {
                            dto.setProductName(name);
                        } else if (log.isDebugEnabled()) {
                            log.debug("未找到对应的商品: entryId={}, productId={}",
                                    entry.getId(), productId);
                        }
                    }
                    
                    // 回填单位名称
                    String unitCode = entry.getBaseUnit();
                    if (unitCode != null && !unitCode.trim().isEmpty()) {
                        String unitName = unitNameMap.get(unitCode);
                        if (unitName != null) {
                            dto.setBaseUnitName(unitName);
                        } else if (log.isDebugEnabled()) {
                            log.debug("未找到对应的单位: entryId={}, unitCode={}",
                                    entry.getId(), unitCode);
                        }
                    }
                    
                    return dto;
                })
                .collect(Collectors.toList());
    }
    
    @Override
    public PriceListEntryDTO getPriceEntryByProduct(String priceListId, String productId) {
        log.debug("查询商品的价格条目: priceListId={}, productId={}", priceListId, productId);
        
        return priceListEntryRepository.findByPriceListIdAndProductIdAndIsDeleted(priceListId, productId, false)
                .map(PriceListEntryDTO::from)
                .orElse(null);
    }
    
    // ==================== 价格查询 ====================
    
    @Override
    public PriceListEntryDTO getCurrentPrice(String productId) {
        log.debug("查询商品当前价格: productId={}", productId);
        
        // 1. 获取当前生效的价目表
        PriceList currentPriceList = priceListRepository.findCurrentEffectivePriceList(LocalDateTime.now())
                .orElse(null);
        
        if (currentPriceList == null) {
            log.warn("当前无生效的价目表");
            return null;
        }
        
        // 2. 查询该商品的价格条目
        return priceListEntryRepository.findByPriceListIdAndProductIdAndIsDeleted(currentPriceList.getId(), productId, false)
                .map(PriceListEntryDTO::from)
                .orElse(null);
    }
    
    @Override
    public Money getCurrentUnitPrice(String productId) {
        PriceListEntryDTO priceEntry = getCurrentPrice(productId);
        return priceEntry != null ? Money.of(priceEntry.getUnitPrice().getAmount()) : null;
    }
    
    @Override
    public Map<String, PriceListEntryDTO> getCurrentPrices(List<String> productIds) {
        log.debug("批量查询商品当前价格: count={}", productIds.size());
        
        Map<String, PriceListEntryDTO> result = new HashMap<>();
        
        // 1. 获取当前生效的价目表
        PriceList currentPriceList = priceListRepository.findCurrentEffectivePriceList(LocalDateTime.now())
                .orElse(null);
        
        if (currentPriceList == null) {
            log.warn("当前无生效的价目表");
            return result;
        }
        
        // 2. 批量查询价格条目
        for (String productId : productIds) {
            priceListEntryRepository.findByPriceListIdAndProductIdAndIsDeleted(currentPriceList.getId(), productId, false)
                    .ifPresent(entry -> result.put(productId, PriceListEntryDTO.from(entry)));
        }
        
        return result;
    }
    
    @Override
    public List<ProductListItemDTO> getCurrentPriceListProducts() {
        log.debug("基于当前价目表查询可展示商品");

        // 1. 获取当前激活且生效的价目表
        PriceList currentPriceList = priceListRepository.findCurrentEffectivePriceList(LocalDateTime.now())
                .orElse(null);

        if (currentPriceList == null) {
            log.info("当前无生效的价目表，返回空商品列表");
            return Collections.emptyList();
        }

        log.debug("找到当前生效价目表: id={}, name={}", currentPriceList.getId(), currentPriceList.getName());

        // 2. 获取该价目表下的所有价格条目
        List<PriceListEntry> priceEntries = priceListEntryRepository
                .findByPriceListIdAndIsDeleted(currentPriceList.getId(), false);

        if (priceEntries.isEmpty()) {
            log.info("当前价目表中无商品条目");
            return Collections.emptyList();
        }

        // 3. 提取商品ID列表（去重）
        Set<String> productIds = priceEntries.stream()
                .map(PriceListEntry::getProductId)
                .filter(id -> id != null && !id.trim().isEmpty())
                .collect(Collectors.toSet());

        if (productIds.isEmpty()) {
            return Collections.emptyList();
        }

        // 4. 批量查询商品信息（只保留已上架且未删除的商品）
        List<Product> products = productRepository.findAllById(productIds).stream()
                .filter(p -> p.getStatus() == ProductStatus.ACTIVE && !p.getIsDeleted())
                .collect(Collectors.toList());

        if (products.isEmpty()) {
            log.info("价目表中的商品均未上架或已删除");
            return Collections.emptyList();
        }

        // 5. 创建商品ID到价格条目的映射
        Map<String, PriceListEntry> priceEntryMap = priceEntries.stream()
                .collect(Collectors.toMap(
                        PriceListEntry::getProductId,
                        entry -> entry,
                        (e1, e2) -> e1  // 如果有重复，保留第一个
                ));

        // 6. 转换为DTO并填充价格信息
        List<ProductListItemDTO> productDTOs = products.stream()
                .filter(product -> priceEntryMap.containsKey(product.getId()))
                .map(product -> {
                    ProductListItemDTO dto = ProductListItemDTO.from(product);
                    PriceListEntry priceEntry = priceEntryMap.get(product.getId());

                    // 填充价格和单位信息
                    dto.setOriginalPrice(Money.of(priceEntry.getUnitPrice()) != null ?
                            MoneyDTO.from(Money.of(priceEntry.getUnitPrice())) : null);
                    dto.setUnit(priceEntry.getBaseUnit());

                    return dto;
                })
                .collect(Collectors.toList());

        // 7. 计算促销折扣信息
        fillDiscountInfo(productDTOs);

        log.debug("最终返回 {} 个可展示商品", productDTOs.size());
        return productDTOs;
    }

    /**
     * 填充折扣信息
     */
    private void fillDiscountInfo(List<ProductListItemDTO> productDTOs) {
        productDTOs.forEach(product -> {
            MoneyDTO originalPrice = product.getOriginalPrice();
            if (originalPrice == null) {
                return;
            }

            // 计算折扣后的当前价格
            try {
                DiscountResult discountResult = promotionService.calculateItemDiscount(
                        product.getId(), originalPrice.getAmount());

                if (discountResult.hasDiscount()) {
                    // 有折扣
                    MoneyDTO currentPrice = MoneyDTO.builder()
                            .amount(discountResult.getDiscountedAmount())
                            .currency(originalPrice.getCurrency())
                            .build();
                    product.setCurrentPrice(currentPrice);
                    product.setHasDiscount(true);
                    product.setDiscountDesc(discountResult.getDescription());
                } else {
                    // 无折扣，当前价格等于原价
                    product.setCurrentPrice(originalPrice);
                    product.setHasDiscount(false);
                }
            } catch (Exception e) {
                log.error("计算商品折扣失败: productId={}", product.getId(), e);
                product.setCurrentPrice(originalPrice);
                product.setHasDiscount(false);
            }
        });
    }

    @Override
    public boolean hasCurrentPrice(String productId) {
        return getCurrentPrice(productId) != null;
    }
    
    @Override
    public boolean isProductInActivePriceList(String productId) {
        log.debug("检查商品是否在激活的价目表中: productId={}", productId);
        
        // 1. 获取所有激活状态的价目表
        List<PriceList> activePriceLists = priceListRepository.findByStatusAndIsDeleted(PriceListStatus.ACTIVE, false);
        
        if (activePriceLists.isEmpty()) {
            return false;
        }
        
        // 2. 检查这些价目表中是否包含该商品
        for (PriceList priceList : activePriceLists) {
            Optional<PriceListEntry> entry = priceListEntryRepository
                    .findByPriceListIdAndProductIdAndIsDeleted(priceList.getId(), productId, false);
            if (entry.isPresent()) {
                log.debug("商品在激活的价目表中: productId={}, priceListId={}, priceListName={}", 
                        productId, priceList.getId(), priceList.getName());
                return true;
            }
        }
        
        return false;
    }
    
    @Override
    public List<PriceListSummaryDTO> getActivePriceListsContainingProduct(String productId) {
        log.debug("获取包含指定商品的激活价目表: productId={}", productId);
        
        // 1. 获取所有激活状态的价目表
        List<PriceList> activePriceLists = priceListRepository.findByStatusAndIsDeleted(PriceListStatus.ACTIVE, false);
        
        if (activePriceLists.isEmpty()) {
            return Collections.emptyList();
        }
        
        // 2. 过滤出包含该商品的价目表
        return activePriceLists.stream()
                .filter(priceList -> {
                    Optional<PriceListEntry> entry = priceListEntryRepository
                            .findByPriceListIdAndProductIdAndIsDeleted(priceList.getId(), productId, false);
                    return entry.isPresent();
                })
                .map(PriceListSummaryDTO::from)
                .collect(Collectors.toList());
    }
}

